package my.edu.model.bills.purchase.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import my.edu.common.constant.MessageConstant;
import my.edu.common.constant.OrderConstant;
import my.edu.common.domain.PageDTO;
import my.edu.common.domain.PageVO;
import my.edu.common.domain.OrderProductDetail;
import my.edu.common.exception.BillsException;
import my.edu.common.exception.Order.AuditException;
import my.edu.common.domain.purchase.PriceAndQuantity;
import my.edu.common.exception.Order.DelOrderException;
import my.edu.common.exception.Order.PurchaseException;
import my.edu.common.utils.PageUtils;
import my.edu.constant.BillsType;
import my.edu.constant.DeliveryMethod;
import my.edu.constant.OrderNoConstant;
import my.edu.model.User.service.IUserService;
import my.edu.model.bills.purchase.entity.*;
import my.edu.model.bills.purchase.entity.dto.*;
import my.edu.model.bills.purchase.entity.vo.PurchaseDetailOrderVO;
import my.edu.model.bills.purchase.entity.vo.PurchaseOrderVO;
import my.edu.model.bills.purchase.entity.vo.PurchaseReportVO;
import my.edu.model.bills.purchase.mapper.PurchaseOrderMapper;
import my.edu.model.bills.sales.entity.SalesOrder;
import my.edu.model.commodity.service.IProductService;
import my.edu.model.information.entity.SupplierPayableBalanceDetail;
import my.edu.model.information.service.IAccountService;
import my.edu.model.information.service.ISupplierService;
import my.edu.utils.OrderNoUtil;
import my.edu.utils.OrderServiceUtil;
import my.edu.utils.TimeUtil;
import my.edu.websocket.BillWebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.*;
import java.util.*;

@Service
public class PurchaseOrderServiceImpl extends ServiceImpl<PurchaseOrderMapper, PurchaseOrder> implements IPurchaseOrderService {

    private record PurchaserOrderDTOResult(List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList,
                                           List<PurchaseDetailOrderDTO> purchaseDetailDTOList,
                                           PriceAndQuantity priceAndQuantity) {
    }

    @Autowired
    private IPurchaseOrderDetailService purchaseOrderDetailService;
    @Autowired
    private IPurchaseSalesExpensesService purchaseSalesExpensesService;
    @Autowired
    private DeliveryMethod deliveryMethod;
    @Autowired
    private IAccountService accountService;
    @Autowired
    private OrderNoConstant orderNoConstant;
    @Autowired
    private ISupplierService supplierService;
    @Autowired
    private IProductService productService;
    @Autowired
    private IUserService userService;

    @Autowired
    private OrderServiceUtil orderServiceUtil;
    @Autowired
    private IPurchaseReturnOrderDetailService purchaseReturnOrderDetailService;
    @Autowired
    private BillWebSocket billWebSocket;

    @Override
    @Transactional
    public void saveNew(PurchaseDTO purchaseDTO, String status) {
        PurchaserOrderDTOResult result = getDTOResult(purchaseDTO, status);
        PurchaseOrder purchaseOrder = setOrderField(BeanUtil.copyProperties(purchaseDTO, PurchaseOrder.class, "id", "purchaseDetailDTOList", "purchaseSalesExpensesDTOList"), result, true);
        save(purchaseOrder);
        //保存detail和采购费用
        purchaseOrderDetailService.saveBatchByDTO(result.purchaseDetailDTOList(), purchaseOrder.getId());
        if (result.purchaseSalesExpensesDTOList() != null && !result.purchaseSalesExpensesDTOList.isEmpty())
            purchaseSalesExpensesService.saveBatchByDTO(BillsType.PURCHASE, result.purchaseSalesExpensesDTOList(), purchaseOrder.getId(), purchaseOrder.getSupplierId(), purchaseOrder.getSupplierName());
        //更新供应商的应付价格
        if (!purchaseOrder.getPaymentStatus().equals(OrderConstant.GET_PAYMENT))
            supplierService.addPayableBalanceDetails(getPayableBalance(purchaseOrder));
        billWebSocket.sendToAllClient(BillsType.PURCHASE,"单据类型：采购单;单据编号："+purchaseOrder.getOrderNo()+";提交人："+purchaseOrder.getCreatedName());
    }


    @Override
    @Transactional
    public void updateOrder(PurchaseDTO purchaseDTO, String status) {
        //存在性和有无审核校验
        PurchaseOrder purchaseOrder = getById(purchaseDTO.getId());
        if (purchaseOrder == null) throw new PurchaseException(MessageConstant.ORDER_NOT_EXIST);
        if (purchaseOrder.getIsAudited() != null && purchaseOrder.getIsAudited() == 1)
            throw new BillsException(MessageConstant.ISAUDIT_CAN_NOT_UPDATE);
        if (purchaseOrder.getPurchaseReturnOrderId() != null && purchaseOrder.getPurchaseReturnOrderId() != 0)
            throw new BillsException(MessageConstant.ISRETURN_CAN_NOT_UPDATE);

        //校验其他字段
        PurchaserOrderDTOResult result = getDTOResult(purchaseDTO, status);
        //设置更新字段
        BeanUtil.copyProperties(purchaseDTO, purchaseOrder, "id", "purchaseDetailDTOList", "purchaseSalesExpensesDTOList");
        setOrderField(purchaseOrder, result, false);
        updateById(purchaseOrder);
        //保存detail和采购费用
        purchaseOrderDetailService.updateBatchByDTO(result.purchaseDetailDTOList, purchaseOrder.getId());
        purchaseSalesExpensesService.updateBatchByDTO(purchaseOrder.getId(), BillsType.PURCHASE, result.purchaseSalesExpensesDTOList, purchaseOrder.getId(), purchaseOrder.getSupplierId(), purchaseOrder.getSupplierName());
        supplierService.updatePayableBalanceDetails(getPayableBalance(purchaseOrder));
        billWebSocket.sendToAllClient(BillsType.PURCHASE,"更新;单据类型：采购单;单据编号："+purchaseOrder.getOrderNo()+";提交人："+purchaseOrder.getUpdateName());
    }

    @Override
    @Transactional
    public void removeOrder(List<Long> ids) {
        List<PurchaseOrder> purchaseOrders = listByIds(ids);
        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            if (purchaseOrder.getIsAudited() != null && purchaseOrder.getIsAudited() == 1)
                throw new DelOrderException(purchaseOrder.getOrderNo() + MessageConstant
                        .ISAUDIT_CAN_NOT_DEL);
        }
        removeBatchByIds(purchaseOrders);
        purchaseOrderDetailService.remove(Wrappers.<PurchaseOrderDetail>lambdaQuery().in(PurchaseOrderDetail::getPurchaseOrderId, ids));
        purchaseSalesExpensesService.removeByOrderTypeAndId(BillsType.PURCHASE, ids);
        //更新供应商的应付价格
        supplierService.removePayableBalanceDetails(ids, BillsType.PURCHASE);
    }


    @Override
    @Transactional
    public void auditOrder(List<Long> ids) {
        //检查是否存在
        List<PurchaseOrder> purchaseOrders = listByIds(ids);
        if (purchaseOrders.isEmpty()) throw new PurchaseException(MessageConstant.ORDER_NOT_EXIST);
        //检查是否已经审核
        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            if (purchaseOrder.getIsAudited() != null && purchaseOrder.getIsAudited() == 1)
                throw new AuditException(purchaseOrder.getOrderNo() + MessageConstant.ISAUDITED);
        }
        orderServiceUtil.setAuditStatus(this, ids, true);
        //更新库存
        List<Long> purchaseIdlist = purchaseOrders.stream().map(PurchaseOrder::getId).toList();
        List<OrderProductDetail> orderProductDetails = purchaseOrderDetailService
                .list(Wrappers.<PurchaseOrderDetail>lambdaQuery()
                        .in(PurchaseOrderDetail::getPurchaseOrderId, purchaseIdlist))
                .stream().map(i -> (OrderProductDetail) i).toList();
        productService.addCurrentStockAndSetLastPurchasePrice(orderProductDetails);
        Map<Long, BigDecimal> accountIdToTotalAmountMap = orderServiceUtil.getAccountIdToTotalAmountMap(purchaseOrders);
        accountService.subBalance(accountIdToTotalAmountMap);
    }

    @Override
    @Transactional
    public void rauditOrder(List<Long> ids) {
        List<PurchaseOrder> purchaseOrders = listByIds(ids);
        if (purchaseOrders.isEmpty()) throw new PurchaseException(MessageConstant.ORDER_NOT_EXIST);
        for (PurchaseOrder purchaseOrder : purchaseOrders) {
            if (purchaseOrder.getIsAudited() != null && purchaseOrder.getIsAudited() == 0)
                throw new AuditException(purchaseOrder.getOrderNo() + OrderConstant.NOTAUDITED);
            if (purchaseOrder.getPurchaseReturnOrderId() != null && purchaseOrder.getPurchaseReturnOrderId() != 0)
                throw new BillsException(MessageConstant.ISRETURN_CAN_NOT_AUDIT + "，编号:" + purchaseOrder.getOrderNo());
        }

        lambdaUpdate()
                .set(PurchaseOrder::getIsAudited, 0)
                .set(PurchaseOrder::getAuditorId, null)
                .set(PurchaseOrder::getAuditorName, null)
                .in(PurchaseOrder::getId, ids)
                .update();

        //更新库存
        List<Long> purchaseIdlist = purchaseOrders.stream().map(PurchaseOrder::getId).toList();
        List<OrderProductDetail> orderProductDetails = purchaseOrderDetailService
                .list(Wrappers.<PurchaseOrderDetail>lambdaQuery()
                        .in(PurchaseOrderDetail::getPurchaseOrderId, purchaseIdlist))
                .stream().map(i -> (OrderProductDetail) i).toList();
        productService.subCurrentStock(orderProductDetails);
        Map<Long, BigDecimal> accountIdToTotalAmountMap = orderServiceUtil.getAccountIdToTotalAmountMap(purchaseOrders);
        accountService.addBalance(accountIdToTotalAmountMap);
    }

    @Override
    public PageVO<PurchaseOrderVO> getPurchaseOrderPage(PageDTO page, PurchaseOrderSearchDTO purchaseOrderSearchDTO) {
        // 构造查询条件
        LambdaQueryWrapper<PurchaseOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper
                .like(purchaseOrderSearchDTO.getOrderNo() != null && !purchaseOrderSearchDTO.getOrderNo().isEmpty(),
                        PurchaseOrder::getOrderNo, purchaseOrderSearchDTO.getOrderNo())
                .between(purchaseOrderSearchDTO.getBeginTime() != null,
                        PurchaseOrder::getOrderDate, purchaseOrderSearchDTO.getBeginTime(), purchaseOrderSearchDTO.getEndTime())
                .eq(purchaseOrderSearchDTO.getDeliveryMethod() != null,
                        PurchaseOrder::getDeliveryMethod, purchaseOrderSearchDTO.getDeliveryMethod())
                .eq(purchaseOrderSearchDTO.getPaymentStatus() != null && !purchaseOrderSearchDTO.getPaymentStatus().isEmpty(),
                        PurchaseOrder::getPaymentStatus, purchaseOrderSearchDTO.getPaymentStatus())
                .eq(purchaseOrderSearchDTO.getReturnStatus() != null && !purchaseOrderSearchDTO.getReturnStatus().isEmpty(),
                        PurchaseOrder::getReturnStatus, purchaseOrderSearchDTO.getReturnStatus())
                .eq(purchaseOrderSearchDTO.getIsAudited() != null,
                        PurchaseOrder::getIsAudited, purchaseOrderSearchDTO.getIsAudited())
                .eq(purchaseOrderSearchDTO.getSalesmanId() != null,
                        PurchaseOrder::getSalesmanId, purchaseOrderSearchDTO.getSalesmanId())
                .eq(purchaseOrderSearchDTO.getPurchaseReturnOrderId() != null,
                        PurchaseOrder::getPurchaseReturnOrderId, purchaseOrderSearchDTO.getPurchaseReturnOrderId())
                .eq(purchaseOrderSearchDTO.getSettlementAccountId() != null,
                        PurchaseOrder::getSettlementAccountId, purchaseOrderSearchDTO.getSettlementAccountId())
                .eq(purchaseOrderSearchDTO.getAuditorId() != null,
                        PurchaseOrder::getAuditorId, purchaseOrderSearchDTO.getAuditorId())
                .eq(purchaseOrderSearchDTO.getLogisticsId() != null,
                        PurchaseOrder::getLogisticsId, purchaseOrderSearchDTO.getLogisticsId())
                .eq(purchaseOrderSearchDTO.getSupplierId() != null,
                        PurchaseOrder::getSupplierId, purchaseOrderSearchDTO.getSupplierId());
        int offset = (page.getPage() - 1) * page.getSize();
        long size = page.getSize();
        Map<String, Object> params = new HashMap<>();
        params.put("offset", offset);
        params.put("size", size);
        long count = count(wrapper);
        if (count == 0) {
            return PageUtils.toPage(new ArrayList<>(), count);
        } else {
            List<PurchaseOrderVO> purchaseOrderVOIPage = baseMapper.selectWithPage(params, wrapper);
            return PageUtils.toPage(purchaseOrderVOIPage, count);
        }
    }

    @Override
    public PurchaseOrderVO getOrderOne(Long id) {
        MPJLambdaWrapper<PurchaseOrder> wrapper = new MPJLambdaWrapper<>();
        wrapper
                .selectAsClass(PurchaseOrder.class, PurchaseOrderVO.class)
                .selectCollection(PurchaseOrderDetail.class, PurchaseOrderVO::getPurchaseDetailDTOList)
                .selectCollection(PurchaseSalesExpenses.class, PurchaseOrderVO::getPurchaseSalesExpensesDTOList)
                .leftJoin(PurchaseOrderDetail.class, PurchaseOrderDetail::getPurchaseOrderId, PurchaseOrder::getId)
                .leftJoin(PurchaseSalesExpenses.class, on -> on
                        .eq(PurchaseSalesExpenses::getSourceDocumentId, PurchaseOrder::getId)
                        .eq(PurchaseSalesExpenses::getBillsType, BillsType.PURCHASE))
                .eq(PurchaseOrder::getId, id);
        return baseMapper.selectJoinOne(PurchaseOrderVO.class, wrapper);
    }

    @Override
    @Transactional
    public void updatePurchaseReturnOrderId(PurchaseReturnOrder purchaseReturnOrder, List<OrderProductDetail> orderProductDetails) {
        String string = checkProductIdAndQuantity(orderProductDetails, purchaseReturnOrder);
        lambdaUpdate()
                .set(PurchaseOrder::getPurchaseReturnOrderId, purchaseReturnOrder.getId())
                .set(PurchaseOrder::getPurchaseReturnOrderNo, purchaseReturnOrder.getOrderNo())
                .set(PurchaseOrder::getReturnStatus, string)
                .eq(PurchaseOrder::getId, purchaseReturnOrder.getPurchaseOrderId())
                .update();
    }

    private String checkProductIdAndQuantity(List<OrderProductDetail> orderProductDetails, PurchaseReturnOrder purchaseReturnOrder) {
        //根据退货单记录的购货单id查询购货单单据
        PurchaseOrder purchaseOrder = getOne(Wrappers.<PurchaseOrder>lambdaQuery().eq(PurchaseOrder::getId, purchaseReturnOrder.getPurchaseOrderId()));
        if (purchaseOrder.getIsAudited() == null || purchaseOrder.getIsAudited() == 0)
            throw new BillsException(MessageConstant.PURCHASEORDER_NOTAUDITED);
        if (purchaseOrder.getPurchaseReturnOrderId() != null && purchaseOrder.getPurchaseReturnOrderId() != 0 && !purchaseOrder.getPurchaseReturnOrderId().equals(purchaseReturnOrder.getId()))
            throw new BillsException(MessageConstant.HAHRETURNED);
        //查询原购货单的购货单明细
        List<OrderProductDetail> sorceorderProductDetails = purchaseOrderDetailService.list(Wrappers.<PurchaseOrderDetail>lambdaQuery().eq(PurchaseOrderDetail::getPurchaseOrderId, purchaseOrder.getId()))
                .stream().map(i -> (OrderProductDetail) i).toList();
        //检查每个退货的数量是否超出购货单的数量
        for (OrderProductDetail orderProductDetail : orderProductDetails) {
            List<OrderProductDetail> product = sorceorderProductDetails.stream().filter(i -> i.getProductId().equals(orderProductDetail.getProductId())).toList();
            if (product.isEmpty()) throw new PurchaseException(MessageConstant.PRODUCT_NOT_RITGHT);
            Integer productQuantity = product.get(0).getQuantity();
            if (orderProductDetail instanceof PurchaseReturnDetailOrderDTO)
                ((PurchaseReturnDetailOrderDTO) orderProductDetail).setSourceQuantity(productQuantity);

            if (productQuantity < orderProductDetail.getQuantity())
                throw new PurchaseException(MessageConstant.PRODUCT_NOT_RITGHT);
        }
        Integer sorceq = purchaseOrder.getQuantity();
        if (purchaseReturnOrder.getQuantity().equals(0)) return OrderConstant.NOT_RETURN;
        int i = sorceq - purchaseReturnOrder.getQuantity();
        return switch (i) {
            case 0 -> OrderConstant.GET_RETURN;
            default -> OrderConstant.PART_RETURN;
        };
    }

    @Override
    @Transactional
    public void updatePurchaseReturnOrderId(List<Long> returnOrderIds, PurchaseReturnOrder purchaseReturnOrder, List<OrderProductDetail> orderProductDetails) {
        //删除原先
        lambdaUpdate()
                .set(PurchaseOrder::getPurchaseReturnOrderId, null)
                .set(PurchaseOrder::getPurchaseReturnOrderNo, null)
                .set(PurchaseOrder::getReturnStatus, OrderConstant.NOT_RETURN)
                .in(PurchaseOrder::getPurchaseReturnOrderId, returnOrderIds)
                .update();
        //新增
        if (purchaseReturnOrder.getPurchaseOrderId() != null)
            updatePurchaseReturnOrderId(purchaseReturnOrder, orderProductDetails);
    }

    @Override
    @Transactional
    public void removePurchaseReturnOrderId(List<Long> returnOrderIds) {
        lambdaUpdate()
                .set(PurchaseOrder::getPurchaseReturnOrderId, null)
                .set(PurchaseOrder::getPurchaseReturnOrderNo, null)
                .set(PurchaseOrder::getReturnStatus, OrderConstant.NOT_RETURN)
                .in(PurchaseOrder::getPurchaseReturnOrderId, returnOrderIds)
                .update();
    }

    @Override
    public List<PurchaseOrderVO> listOnly(PurchaseOrderSearchDTO purchaseOrderSearchDTO) {
        return list(Wrappers.<PurchaseOrder>lambdaQuery()
                .like(purchaseOrderSearchDTO.getOrderNo() != null && !purchaseOrderSearchDTO.getOrderNo().isEmpty(),
                        PurchaseOrder::getOrderNo, purchaseOrderSearchDTO.getOrderNo())
                .between(purchaseOrderSearchDTO.getBeginTime() != null,
                        PurchaseOrder::getOrderDate, purchaseOrderSearchDTO.getBeginTime(), purchaseOrderSearchDTO.getEndTime())
                .eq(purchaseOrderSearchDTO.getPaymentStatus() != null && !purchaseOrderSearchDTO.getPaymentStatus().isEmpty(),
                        PurchaseOrder::getPaymentStatus, purchaseOrderSearchDTO.getPaymentStatus())
                .eq(purchaseOrderSearchDTO.getIsAudited() != null,
                        PurchaseOrder::getIsAudited, purchaseOrderSearchDTO.getIsAudited())
                .eq(purchaseOrderSearchDTO.getSalesmanId() != null,
                        PurchaseOrder::getSalesmanId, purchaseOrderSearchDTO.getSalesmanId())
                .eq(purchaseOrderSearchDTO.getAuditorId() != null,
                        PurchaseOrder::getAuditorId, purchaseOrderSearchDTO.getAuditorId())
                .eq(purchaseOrderSearchDTO.getSupplierId() != null,
                        PurchaseOrder::getSupplierId, purchaseOrderSearchDTO.getSupplierId())
                .orderByDesc(PurchaseOrder::getCreateTime)).stream().map(i -> BeanUtil.copyProperties(i, PurchaseOrderVO.class)).toList();
    }

    @Override
    public void checkPurchaseOrder(PurchaseReturnDTO purchaseReturnDTO) {
        Long purchaseOrderId = purchaseReturnDTO.getPurchaseOrderId();
        if (purchaseOrderId != null && purchaseOrderId != 0) {
            List<PurchaseReturnDetailOrderDTO> purchaseReturnDetailDTOList = purchaseReturnDTO.getPurchaseReturnDetailDTOList();
            PurchaseOrderVO orderOne = getOrderOne(purchaseOrderId);
            if (orderOne == null) throw new BillsException(MessageConstant.ORDER_NOT_EXIST);
            //插入源单据采购数量
            purchaseReturnDTO.setSourcePurchaseQuantity(orderOne.getQuantity());
            //检查每样商品是否超出源单据数量
            for (PurchaseDetailOrderVO purchaseDetailOrder : orderOne.getPurchaseDetailDTOList()) {
                PurchaseReturnDetailOrderDTO purchaseReturnDetailOrderDTO = purchaseReturnDetailDTOList.stream()
                        .filter(detail -> detail.getProductId().equals(purchaseDetailOrder.getProductId())).findFirst().get();
                purchaseReturnDetailOrderDTO.setSourceQuantity(purchaseDetailOrder.getQuantity());
                if (purchaseReturnDetailOrderDTO.getQuantity() > purchaseReturnDetailOrderDTO.getSourceQuantity())
                    throw new BillsException(MessageConstant.OVERMAX_SOURCEQUANTITY);
            }
        }
    }

    @Override
    public BigDecimal getTodayPurchase() {
        List<PurchaseOrder> list = lambdaQuery()
                .between(PurchaseOrder::getCreateTime, TimeUtil.getTodayStartTime(), TimeUtil.getTodayEndTime())
                .list();
        return getPaidAmountTotalInOrder(list);
    }

    @Override
    public BigDecimal getMonthPurchase() {
        // 获取当前月份的第一天和最后一天
        LocalDate firstDayOfMonth = YearMonth.now().atDay(1);
        LocalDate lastDayOfMonth = YearMonth.now().atEndOfMonth();

        // 假设你有一个方法可以根据日期范围查询采购金额
        List<PurchaseOrder> list = lambdaQuery()
                .between(PurchaseOrder::getCreateTime, firstDayOfMonth, lastDayOfMonth)
                .list();
        return getPaidAmountTotalInOrder(list);
    }

    @Override
    public BigDecimal getYesterdayPurchase() {
        // 获取昨天的日期
        LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
        List<PurchaseOrder> list = lambdaQuery()
                .between(PurchaseOrder::getCreateTime, TimeUtil.getDayStartTime(yesterday), TimeUtil.getDayEndTime(yesterday))
                .list();
        return getPaidAmountTotalInOrder(list);
    }

    @Override
    public BigDecimal getYearPurchase() {
        // 假设你有一个方法可以根据日期范围查询采购金额
        List<PurchaseOrder> list = lambdaQuery()
                .between(PurchaseOrder::getCreateTime, TimeUtil.getStartOfYear(), TimeUtil.getTodayEndTime())
                .list();
        return getPaidAmountTotalInOrder(list);
    }

    @Override
    public Map<YearMonth, BigDecimal> getPurchasePriceList() {
        LinkedHashMap<YearMonth, BigDecimal> map = new LinkedHashMap<>();
        LocalDate currentDate = LocalDate.now();
        YearMonth currentYearMonth = YearMonth.from(currentDate);
        // 添加当前月份
        LocalDateTime firstDayOfMonth = currentYearMonth.atDay(1).atTime(LocalTime.MIN);
        LocalDateTime lastDayOfMonth = currentYearMonth.atEndOfMonth().atTime(LocalTime.MAX);
        List<PurchaseOrder> list = lambdaQuery().between(PurchaseOrder::getCreateTime, firstDayOfMonth, lastDayOfMonth).list();
        map.put(currentYearMonth, getPaidAmountTotalInOrder(list));

        // 添加前六个月的月份
        for (int i = 1; i <= 6; i++) {
            currentYearMonth = currentYearMonth.minusMonths(1);
            firstDayOfMonth = currentYearMonth.atDay(1).atTime(LocalTime.MIN);
            lastDayOfMonth = currentYearMonth.atEndOfMonth().atTime(LocalTime.MAX);
            list = lambdaQuery().between(PurchaseOrder::getCreateTime, firstDayOfMonth, lastDayOfMonth).list();
            map.put(currentYearMonth, getPaidAmountTotalInOrder(list));
        }

        return orderServiceUtil.reverseMap(map);
    }

    @Override
    public JSONObject getPurchaseReportList(PageDTO pageDTO, PurchaseOrderSearchDTO purchaseOrderSearchDTO) {
        //查询采购与退货的详情
//        MPJLambdaWrapper<PurchaseOrder> wrapper = new MPJLambdaWrapper<PurchaseOrder>()
//                .selectAll(PurchaseOrderDetail.class)
//                .leftJoin(PurchaseOrderDetail.class, PurchaseOrderDetail::getPurchaseOrderId, PurchaseOrder::getId)
//                .between(purchaseOrderSearchDTO.getBeginTime() != null,
//                        PurchaseOrder::getOrderDate, purchaseOrderSearchDTO.getBeginTime(), purchaseOrderSearchDTO.getEndTime())
//                .eq(purchaseOrderSearchDTO.getSupplierId()!= null,
//                        PurchaseOrder::getSupplierId, purchaseOrderSearchDTO.getSupplierId())
//                .and(StringUtils.hasText(purchaseOrderSearchDTO.getMaterialParam()), i->i
//                        .like(PurchaseOrderDetail::getProductNo, purchaseOrderSearchDTO.getMaterialParam())
//                        .or()
//                        .like(PurchaseOrderDetail::getProductName, purchaseOrderSearchDTO.getMaterialParam()));
//
        List<PurchaseOrderDetail> reportList = purchaseOrderDetailService.getReportList(purchaseOrderSearchDTO);
        List<PurchaseReturnOrderDetail> returnReportList = purchaseReturnOrderDetailService.getReportList(purchaseOrderSearchDTO);

        Map<Long, PurchaseReportVO> map = new HashMap<>();
        BigDecimal realityPriceTotal = BigDecimal.ZERO;
        for (PurchaseOrderDetail record : reportList) {
            PurchaseReportVO purchaseReportVO = map.computeIfAbsent(record.getProductId(), i->{
                PurchaseReportVO vo = BeanUtil.copyProperties(record, PurchaseReportVO.class);
                vo.setInSum(0L);
                vo.setOutSum(0L);
                vo.setOutSumPrice(BigDecimal.ZERO);
                vo.setInSumPrice(BigDecimal.ZERO);
                vo.setInOutSumPrice(BigDecimal.ZERO);
                return vo;
            });
            Integer quantity = record.getQuantity();
            BigDecimal multiply = record.getCurrentPrice().multiply(BigDecimal.valueOf(quantity));
            purchaseReportVO.setInSum(quantity + purchaseReportVO.getInSum());
            purchaseReportVO.setInSumPrice(multiply.add(purchaseReportVO.getInSumPrice()));
            realityPriceTotal = realityPriceTotal.add(multiply);
        }

        for (PurchaseReturnOrderDetail record : returnReportList) {
            PurchaseReportVO purchaseReportVO = map.computeIfAbsent(record.getProductId(), i->{
                PurchaseReportVO vo = BeanUtil.copyProperties(record, PurchaseReportVO.class);
                vo.setInSum(0L);
                vo.setOutSum(0L);
                vo.setOutSumPrice(BigDecimal.ZERO);
                vo.setInSumPrice(BigDecimal.ZERO);
                vo.setInOutSumPrice(BigDecimal.ZERO);
                return vo;
            });
            Integer quantity = record.getQuantity();
            BigDecimal multiply = record.getCurrentPrice().multiply(BigDecimal.valueOf(quantity));
            purchaseReportVO.setOutSum(quantity + purchaseReportVO.getOutSum());
            purchaseReportVO.setOutSumPrice(multiply.add(purchaseReportVO.getOutSumPrice()));
            realityPriceTotal = realityPriceTotal.subtract(multiply);
        }

        List<PurchaseReportVO> list = map.values().stream()
                .peek(i -> i.setInOutSumPrice(i.getInSumPrice().subtract(i.getOutSumPrice())))
                .toList();

        return new JSONObject()
                .putOnce("realityPriceTotal", realityPriceTotal)
                .putOnce("data", list);
    }

    private PurchaseReportVO newReportVO(OrderProductDetail k){
        PurchaseReportVO vo = BeanUtil.copyProperties(k, PurchaseReportVO.class);
        vo.setInSum(0L);
        vo.setOutSum(0L);
        vo.setOutSumPrice(BigDecimal.ZERO);
        vo.setInSumPrice(BigDecimal.ZERO);
        vo.setInOutSumPrice(BigDecimal.ZERO);
        return vo;
    }

    private BigDecimal getPaidAmountTotalInOrder(List<PurchaseOrder> list) {
        return list.stream().map(PurchaseOrder::getPaidAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
    }


    private PurchaseOrder setOrderField(PurchaseOrder purchaseOrder, PurchaserOrderDTOResult result, boolean isNew) {
        //设置其他字段然后新增
        purchaseOrder.setQuantity(result.priceAndQuantity().getQuantity());//总数量
        purchaseOrder.setPurchaseAmount(result.priceAndQuantity().getAmount());//购货金额
        if (purchaseOrder.getOrderNo() == null || purchaseOrder.getOrderNo().isEmpty()) {
            //设置No
            String orderNo = OrderNoUtil.generateOrderNo(orderNoConstant.getPurchaseNo());
            purchaseOrder.setOrderNo(orderNo);
        } else {
            //检查是否有重复no
            long count = count(Wrappers.<PurchaseOrder>lambdaQuery().eq(PurchaseOrder::getOrderNo, purchaseOrder.getOrderNo()));
            if (isNew && count > 0) throw new BillsException(MessageConstant.ORDER_NO_EXISTS);
        }
        //设置优惠后金额
        BigDecimal amount = purchaseOrder.getPurchaseAmount().subtract(purchaseOrder.getDiscountAmount());
        if (amount.compareTo(BigDecimal.ZERO) < 0) {
            throw new PurchaseException(MessageConstant.AMOUNT_ERROR);
        }
        purchaseOrder.setAmountAfterDiscount(amount);//优惠后金额
        //优惠后金额小于已付款金额
        if (purchaseOrder.getAmountAfterDiscount().compareTo(purchaseOrder.getPaidAmount()) < 0)
            throw new PurchaseException(MessageConstant.AMOUNT_ERROR);
        //设置付款状态
        setPaidStatus(purchaseOrder);
        if (isNew) purchaseOrder.setReturnStatus(OrderConstant.NOT_RETURN);
        purchaseOrder.setIsAudited(0);
        return purchaseOrder;
    }

    private PurchaserOrderDTOResult getDTOResult(PurchaseDTO purchaseDTO, String status) {
        List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList = purchaseDTO.getPurchaseSalesExpensesDTOList();
        List<PurchaseDetailOrderDTO> purchaseDetailDTOList = purchaseDTO.getPurchaseDetailDTOList();
        //检查额外的表存在性，并获取商品的总价格总数量信息
        //检查交货方式
        deliveryMethod.checkDeliveryMethod(purchaseDTO.getDeliveryMethod());
        //检查采购费用
        if (purchaseSalesExpensesDTOList != null)
            extractedSalesExpenses(purchaseDTO, purchaseSalesExpensesDTOList, purchaseDetailDTOList);
        //检查结算账户
        accountService.checkAccount(purchaseDTO.getSettlementAccountId());

        supplierService.checkSupplier(purchaseDTO.getSupplierId());
        userService.checkUser(purchaseDTO.getSalesmanId());

        //校验detail，并返回商品总价和数量
        PriceAndQuantity priceAndQuantity = orderServiceUtil.checkAndGetProductDetail(status, purchaseDetailDTOList);

        PurchaserOrderDTOResult result = new PurchaserOrderDTOResult(purchaseSalesExpensesDTOList, purchaseDetailDTOList, priceAndQuantity);
        return result;
    }


    private void setPaidStatus(PurchaseOrder purchaseOrder) {
        BigDecimal amountAfterDiscount = purchaseOrder.getAmountAfterDiscount();
        if (amountAfterDiscount.compareTo(BigDecimal.ZERO) != 0) {
            BigDecimal paidAmount = purchaseOrder.getPaidAmount();
            if (paidAmount == null) {
                paidAmount = BigDecimal.ZERO;
                purchaseOrder.setPaidAmount(paidAmount);
            }
            //没有付一分钱
            if (paidAmount.compareTo(BigDecimal.ZERO) == 0)
                purchaseOrder.setPaymentStatus(OrderConstant.NOT_PAYMENT);
            else if (amountAfterDiscount.compareTo(paidAmount) == 0)
                //已经完成付款
                purchaseOrder.setPaymentStatus(OrderConstant.GET_PAYMENT);
                //部分付款
            else if (amountAfterDiscount.compareTo(paidAmount) > 0)
                purchaseOrder.setPaymentStatus(OrderConstant.PART_PAYMENT);
            else throw new BillsException(MessageConstant.PAID_AMOUNT_ERROR);
        } else purchaseOrder.setPaymentStatus(OrderConstant.GET_PAYMENT);
    }


    //检查分摊之后的采购费用合计是否和采购总费用一致
    private void extractedSalesExpenses(PurchaseDTO purchaseDTO, List<PurchaseSalesExpensesDTO> purchaseSalesExpensesDTOList, List<PurchaseDetailOrderDTO> purchaseDetailDTOList) {
        //如果存在采购费用，且进行了分摊
        if (purchaseSalesExpensesDTOList != null && !purchaseSalesExpensesDTOList.isEmpty() && purchaseDTO.getIsAllocated() != null && purchaseDTO.getIsAllocated().equals(1)) {
            BigDecimal totalCostInProduct = BigDecimal.ZERO;
            BigDecimal totalCost = BigDecimal.ZERO;
            //获取采购费用
            List<BigDecimal> purchaseSalesExpensesAmountList = purchaseSalesExpensesDTOList.stream().map(PurchaseSalesExpensesDTO::getAmount).toList();
            //获取分摊的采购费用
            List<BigDecimal> procurementCostList = purchaseDetailDTOList.stream().map(PurchaseDetailOrderDTO::getProcurementCost).toList();
            for (BigDecimal bigDecimal : procurementCostList) {
                totalCostInProduct = totalCostInProduct.add(bigDecimal);
            }
            for (BigDecimal bigDecimal : purchaseSalesExpensesAmountList) {
                totalCost = totalCost.add(bigDecimal);
            }
            if (totalCostInProduct.compareTo(totalCost) != 0) {
                throw new PurchaseException(MessageConstant.SAVE_ERROR);
            }
        }
    }

    private SupplierPayableBalanceDetail getPayableBalance(PurchaseOrder purchaseOrder) {
        Long supplierId = purchaseOrder.getSupplierId();
        BigDecimal totalPrice = getTotalPriceFromStatus(purchaseOrder);
        SupplierPayableBalanceDetail detail = SupplierPayableBalanceDetail.builder()
                .billsType(BillsType.PURCHASE)
                .billId(purchaseOrder.getId())
                .supplierId(supplierId)
                .payableBalance(totalPrice)
                .billNo(purchaseOrder.getOrderNo())
                .build();
        return detail;
    }

    private static BigDecimal getTotalPriceFromStatus(PurchaseOrder purchaseOrder) {
        String paymentStatus = purchaseOrder.getPaymentStatus();
        BigDecimal totalPrice;
        switch (paymentStatus) {
            case OrderConstant.NOT_PAYMENT -> {
                totalPrice = purchaseOrder.getAmountAfterDiscount();
            }
            case OrderConstant.PART_PAYMENT -> {
                totalPrice = purchaseOrder.getAmountAfterDiscount().subtract(purchaseOrder.getPaidAmount());
            }
            case OrderConstant.GET_PAYMENT -> {
                totalPrice = BigDecimal.ZERO;
            }
            default -> throw new RuntimeException(MessageConstant.CAN_NOT_FOUND_PAYSTATUS);
        }
        return totalPrice;
    }

}